/* COPYRIGHT_CHUNFENG */
#include "unistd.h"
#include "cf_timer.h"
#include "cf_std.h"
#include "cf_common.h"
#include "lcf_log.h"
static CFTimer* timer_head;



CFTimer* cf_timer_new(struct timeval *expires, void(*function)(void* data), void* data)
{
	CFTimer *new_timer = (CFTimer*)malloc(sizeof(CFTimer));
	memset(new_timer, 0, sizeof(CFTimer));
	cf_list_init(&new_timer->list);
	new_timer->expires.tv_sec = expires->tv_sec;
	new_timer->expires.tv_usec = expires->tv_usec;
	gettimeofday(&new_timer->start_clock, NULL);
	new_timer->function = function;
	new_timer->data = data;
	return new_timer;
}

int cf_timers_init()
{
    struct timeval t;
	timer_head = cf_timer_new(&t, NULL, NULL);
	ualarm(50000, 50000);
	return 0;
}

CFTimer* cf_timer_get_next(CFTimer* timer)
{
	return container_of(cf_list_get_next(&timer->list), CFTimer, list);
}

void cf_timer_delete(CFTimer* timer, CFTimer* to_del)
{
	cf_list_del(&to_del->list);
}

void cf_timer_free(CFTimer* timer)
{
	free(timer);
}

void cf_timer_delete_free(CFTimer* timer, CFTimer* to_delete)
{
	cf_timer_delete(timer, to_delete);
	cf_timer_free(to_delete);
}

void cf_timer_free_list(CFTimer* timer)
{
	CFListContainerForeachSafe(timer, tmpT, CFTimer, list){
		cf_timer_free(tmpT);
	}
}

int cf_timer_add(struct timeval* expires, void(*function)(void* data), void* data)
{
	CFTimer *new_timer = cf_timer_new(expires, function, data);
    if(!timer_head)
		timer_head = new_timer;
	else
		cf_list_insert_pre(&timer_head->list, &new_timer->list);
	return 0;
}
 
int timeval_expired(struct timeval* start, struct timeval* curr, struct timeval* expires)
{
    //LCF_DBG("stat:%d, now: %d, expires:%d\n", start->tv_sec, curr->tv_sec, expires->tv_sec)
	if(curr->tv_sec - start->tv_sec < expires->tv_sec){
        LCF_DBG("1\n");
			return 0;
	}else if(curr->tv_sec - start->tv_sec == expires->tv_sec){
        LCF_DBG("2\n");
		if(curr->tv_usec - start->tv_usec >= expires->tv_usec)
			return 1;
		else 
			return 0;
	}else{
        LCF_DBG("3\n");
		return 1;
	}
}


int cf_timers_trigger()
{
	CFTimer* tmpTimer;
    
	tmpTimer = cf_timer_get_next(timer_head);
    if(tmpTimer == timer_head)
        return 0;
	struct timeval currentTime;
    int i=0;
	while(tmpTimer->function != NULL){
        i++;
		LCF_DBG("do%d\n", i);
		CFTimer* to_check = tmpTimer;
		tmpTimer = cf_timer_get_next(to_check);
		//LCF_DBG("start_clock=%f, current_clock=%f\n", to_check->start_clock/CLOCKS_PER_SEC, clock()/CLOCKS_PER_SEC);
		gettimeofday(&currentTime, 0);
		if(timeval_expired(&to_check->start_clock, &currentTime, &to_check->expires)){
			to_check->function(to_check->data);
			cf_timer_delete_free(timer_head, to_check);
		}
	}
	return 0;
}

int cf_timers_clean()
{
    if(timer_head)
        cf_timer_free_list(timer_head);
	return 0;
}
